"""
玄武平台数据模型类

"""
import json
from datetime import timedelta
from time import time
from uuid import uuid4

from peewee import UUIDField, \
    FloatField, DecimalField, FixedCharField, SmallIntegerField, AutoField

from models.base_model import MetaBaseModel
from models.erp import District
from models.public import EnumData
from models.user import *
from utils.controller import GetStatusNew


class Tenant(MetaBaseModel):
    """
    客户信息详情（包含合作伙伴）
    """
    id = UUIDField(primary_key=True, default=str(uuid4()))
    name = CharField()  # 公司名称
    password_hash = CharField()
    contact = CharField()  # 客户联系人
    email = CharField()
    mobile = CharField()
    company_type = CharField(choices=['IDC运营商', '网络供应商', '云服务商', '行业客户', '政府客户', '其他'])
    phone = CharField(null=True)
    province = CharField(null=True)  # 省
    city = CharField(null=True)  # 市
    district = CharField(null=True)  # 区
    extra = CharField(null=True)  # 详细地址
    description = TextField(null=True)
    parent = ForeignKeyField('self', backref='children', null=True)
    no = TextField(null=True)  # 编号
    official_name = CharField(null=True)  # 客户正式名称
    type = CharField(choices=['tenant', 'body', 'sale'], default='tenant')
    region = CharField(null=True)  # 区域
    body = CharField(null=True)  # 主体id(仅限类型为tenant使用)
    relation = CharField(null=True)  # 销售id(仅为销售自关联使用)
    is_show_flow = IntegerField(default=0)
    flow = TextField(null=True)
    flow_rate = FloatField(default=1)
    erp_cust_id = CharField(null=True)  # 销售id(仅为销售自关联使用)

    class Meta:
        table_name = 'sdn_tenant'


class Vll(MetaBaseModel):
    id = UUIDField(primary_key=True, default=str(uuid4()))
    type = CharField(choices=['d2d', 'd2c', 'c2c', 'multi'], default='d2d')
    delete_time = IntegerField()  # 删除时间
    order_id = CharField(max_length=64, null=True)
    name = CharField()  # 不可为空
    public_cloud = CharField(null=True)  # D2C特有
    status = CharField(choices=['wait_create', 'creating', 'failure', 'stopping', 'servicing', 'wait_delete',
                                'deleting', 'delete_failure'], default='creating')  # 待创建、创建中、创建失败、停止、运行中、待删除、删除中、删除失败
    priority = IntegerField(default=0)  # 业务优先级
    description = TextField(null=True)
    # auto_renew = BooleanField(default=False)  # 自动续订，不可为空
    controller_vni_id = IntegerField(null=True)
    set_path_nodes = TextField()  # 指定路径 节点顺序列表 ,列表转json
    set_second_path_nodes = TextField()  # 备选路径 节点顺序列表 ,列表转json
    auto_switch_path = BooleanField(default=True)  # 是否自动切换路径
    tenant = ForeignKeyField(Tenant, backref='vlls')
    no = TextField(null=True)  # 编号
    success_time = IntegerField()  # 业务成功创建时间
    is_flow_warning = BooleanField(default=False)  # 是否超额告警
    bandwidth_warning_k = DecimalField(10, 6, default=1)  # 超额系数
    is_flow_below = BooleanField(default=False)  # 是否低额告警
    bandwidth_warning_v = DecimalField(10, 6, default=1)
    sync_status = CharField(max_length=64, null=True, default=0)  # 是否同步
    sync_time = IntegerField()
    is_del = BooleanField(default=False)
    creation_time = IntegerField(default=int(time()))

    class Meta:
        table_name = 'sdn_vll'

    def get_status(self):
        if self.status == 'servicing' and self.type != 'multi':
            a_end = self.endpoints.where(Endpoint.name == 'A端', Endpoint.is_del == False)
            if a_end:
                a_end = a_end[0]
                a_logic_status = a_end.logic_port.get_status()
                a_status = True if a_logic_status == 'UP' else False
            else:
                a_end = self.cloud_endpoints.where(CloudEndpoint.name == 'A端', CloudEndpoint.is_del == False).get()
                a_logic_status = a_end.cloud_config.logic_port.get_status()
                a_status = True if a_logic_status == 'UP' else False

            z_end = self.endpoints.where(Endpoint.name == 'Z端', Endpoint.is_del == False)
            if z_end:
                z_end = z_end[0]
                z_logic_status = z_end.logic_port.get_status()
                z_status = True if z_logic_status == 'UP' else False
            else:
                z_end = self.cloud_endpoints.where(CloudEndpoint.name == 'Z端', CloudEndpoint.is_del == False).get()
                z_logic_status = z_end.cloud_config.logic_port.get_status()
                z_status = True if z_logic_status == 'UP' else False
            return 'servicing' if all([a_status, z_status]) else 'fault'
        return self.status

    def get_end(self, name):
        end = Endpoint.get_or_none(Endpoint.vll_id == self.id, Endpoint.name == name, Endpoint.is_del == False)
        if not end:
            end = CloudEndpoint.select().where(CloudEndpoint.vll_id == self.id,
                                               CloudEndpoint.name == name,
                                               CloudEndpoint.is_del == False)
        return end

    def get_vll_traffic(self, start_date, end_date):
        """
        date: 日期
        type: 小时 or 天
        """
        if self.type == 'd2d':
            A_end = Endpoint.get_or_none(vll=self.id, name='A端', is_del=False)
            Z_end = Endpoint.get_or_none(vll=self.id, name='Z端', is_del=False)
            if A_end and Z_end:
                a_traffic = GetStatusNew().get_traffic(conditions={'biz_id': int(A_end.controller_id)},
                                                       start_date=start_date,
                                                       end_date=end_date,
                                                       type='mins')
                z_traffic = GetStatusNew().get_traffic(conditions={'biz_id': int(Z_end.controller_id)},
                                                       start_date=start_date,
                                                       end_date=end_date,
                                                       type='mins')
                return a_traffic, z_traffic

    def get_standard_obj(self, for_show=False):
        import time
        info = model_to_dict(self, only=[Vll.id])

        info['id'] = str(info['id'])
        info['type'] = self.type
        info['vll_show_name'] = self.name
        info['note'] = self.description
        info['org'] = {"id": str(self.tenant.id),
                       "name": self.tenant.name}
        points = Endpoint.select().where(Endpoint.vll_id == self.id, Endpoint.is_del == False)
        endpoint_show_name = ','.join([i.node.name for i in points])
        endpoint_city_name = ','.join([i.node.dc.city.name for i in points])
        endpoint_region_name = ','.join([i.node.dc.region.name for i in points])
        endpoint_dc_name = ','.join([i.node.dc.name for i in points])
        open_time = self.creation_time
        open_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(open_time))
        status = EnumData.get_or_none(EnumData.value == self.get_status(), EnumData.type == 'vll')
        if status:
            info['status'] = status.key
        else:
            info['status'] = self.get_status()
        if self.type == 'multi':
            point_ids = [i.id for i in points]
            extension = VllEndpointExtension.select().where(VllEndpointExtension.relation_id << point_ids,
                                                            VllEndpointExtension.is_del == False)
            if extension:
                extension = extension[0]
            vll_ends = VllEndpointExtension.select().where(VllEndpointExtension.relation_id << point_ids,
                                                           VllEndpointExtension.is_del == False)
            bandwidth = ','.join([str(i.bandwidth) for i in vll_ends])
            info['points'] = []
            end_names = endpoint_show_name.split(',') if endpoint_show_name else []
            ends = Endpoint.select().where(Endpoint.vll_id == self.id, Endpoint.is_del == False)
            num = 1
            for i in range(len(end_names)):
                point = {'name': end_names[i], 'controller_id': ends[i].controller_id, "end_name": "端点" + str(num)}
                point['bandwidth'] = extension.bandwidth if extension else 0
                num += 1
                info['points'].append(point)
        else:

            extension = VllEndpointExtension.get_or_none(VllEndpointExtension.relation_id == self.id,
                                                         VllEndpointExtension.is_del == False)
            bandwidth = "{},{}".format(str(extension.bandwidth), str(extension.bandwidth))
            info['points'] = []

            info['bandwidth'] = extension.bandwidth if extension else ''
            a_end = self.get_end(name='A端')
            z_end = self.get_end(name="Z端")
            info['points'].append(
                {"name": a_end.node.name, "controller_id": a_end.controller_id, 'end_name': a_end.name})
            info['points'].append(
                {"name": z_end.node.name, "controller_id": z_end.controller_id, 'end_name': z_end.name})
            now = datetime.now()
            previous_minute = now - timedelta(minutes=1)
            minute_rounded = previous_minute.replace(second=0, microsecond=0)
            # a_traffic, z_traffic = self.get_vll_traffic(minute_rounded,
            #                                             minute_rounded)
            # a_traffic = a_traffic[-1][str(minute_rounded)]
            # z_traffic = z_traffic[-1][str(minute_rounded)]
            # info['instance_speed'] = max(a_traffic['input_bps'] if a_traffic['input_bps'] else 0,
            #                              z_traffic['output_bps'] if z_traffic['output_bps'] else 0)
            # info['instance_speed'] = round(info['instance_speed'] / 1000 / 1000, 2)
            # info['instance_speed'] = self.instance_speed
        expiration_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(
            extension.expiration_time)) if extension and extension.expiration_time else None
        if self.sync_status == "2":
            if self.no:
                info["no"] = json.loads(self.no)
            else:
                no = []
                from apps.utils.views import generate_no
                if self.type != 'multi':
                    no.append(generate_no('Vll', type='d2d'))
                else:
                    no.append(generate_no('Vll', type='multi'))
                self.no = json.dumps(no)
                info['no'] = no[0]
                self.save()
        info['endpoint_show_name'] = endpoint_show_name
        info['endpoint_city_name'] = endpoint_city_name
        info['endpoint_region_name'] = endpoint_region_name
        info['endpoint_dc_name'] = endpoint_dc_name
        info['open_time'] = open_time
        info['expiration_time'] = expiration_time
        info['endpoint_show_bandwidth'] = bandwidth
        if extension.charge_mode:
            info['charge_type'] = extension.charge_mode
            if extension.charge_mode == 'year_month':
                info['charge_param'] = {
                    "period": "year",  # 计费周期，可以为以下值：month/year/half-year/quarter
                    "period_fee": '',  # 周期费用
                    "once_fee": '',  # 一次性费用
                    "money_unit": "人民币",  # 货币单位
                }
            elif extension.charge_mode == '95_charge':
                info['charge_param'] = {
                    "least_flow": '',  # 保底流量 单位 Mbps
                    "least_price": '',  # 保底价格 单位 元
                    "pass_unit_price": '',  # 超额单价 单位 元/Mbps
                    "once_fee": '',  # 一次性费用
                    "money_unit": "人民币",  # 货币单位
                }

        return info


class Region(MetaBaseModel):
    """
    区域
    """
    id = UUIDField(primary_key=True, default=str(uuid4()))
    name = CharField()  # 不可为空
    description = TextField(null=True)
    is_del = BooleanField(default=False)

    class Meta:
        table_name = 'sdn_region'


class City(MetaBaseModel):
    """
    城市
    """
    id = UUIDField(primary_key=True, default=str(uuid4()))
    name = CharField()  # 不可为空
    latitude = FloatField(null=True)
    longitude = FloatField(null=True)
    description = TextField(null=True)
    region = ForeignKeyField(Region, backref='cities')
    is_del = BooleanField(default=False)

    class Meta:
        table_name = 'sdn_city'


class DataCenter(MetaBaseModel):
    """
    数据中心
    """
    id = UUIDField(primary_key=True, default=str(uuid4()))
    name = CharField()  # 不可为空
    connected_cloud = BooleanField(default=False)  # 是否连云
    description = TextField(null=True)
    # 关联
    city = ForeignKeyField(City, backref='dcs')
    region = ForeignKeyField(Region, backref='dcs')

    # 地理位置
    geo_country = ForeignKeyField(District, backref='coun_dcs')
    geo_province = ForeignKeyField(District, backref='pro_dcs')
    geo_city = ForeignKeyField(District, backref='city_dcs')
    geo_district = ForeignKeyField(District, backref='dis_dcs')
    geo_address = TextField(null=True)
    is_del = BooleanField(default=False)

    class Meta:
        table_name = 'sdn_data_center'


class Node(MetaBaseModel):
    id = UUIDField(primary_key=True, default=str(uuid4()))
    name = CharField(null=True)
    activated = BooleanField(default=False)  # 标识是否为未知设备
    vtep = CharField()  # vtep
    user_vlan = CharField()  # vtep
    controller_id = CharField(null=True)  # 跟controller作对比的id(controller侧id)
    description = TextField(null=True)
    dc = ForeignKeyField(DataCenter, backref='nodes', null=True)
    exist_status = CharField(
        choices=['loss', 'found', 'normal'],
        default='normal')  # 标记节点在控制器和系统数据库中的状态，系统中存在而控制器不存在为loss(丢失)，系统中不存在而控制器中存在为found(发现)
    is_del = BooleanField(default=False)

    class Meta:
        table_name = 'sdn_node'


class Device(MetaBaseModel):
    id = UUIDField(primary_key=True, default=str(uuid4()))
    # 设备固有属性
    hostname = CharField(null=True)
    ip = CharField(null=True)
    vendor = CharField(null=True)  # 厂商
    model = CharField(null=True)  # 型号
    sn = CharField(null=True)
    status = FixedCharField(choices=['UP', 'DOWN'], default='DOWN')
    position = CharField(null=True)  # 位置
    room = CharField(null=True)  # 机房
    rack = CharField(null=True)  # 机架
    description = TextField(null=True)
    port_section = CharField(null=True)
    sign = CharField(choices=['d1', 'd2'], null=True)  # 控制器中标记该设备是堆叠中的d1还是d2
    node = ForeignKeyField(Node, backref='devices', null=True)
    exist_status = CharField(
        choices=['loss', 'found', 'normal'],
        default='normal')  # 标记设备在控制器和系统数据库中的状态，系统中存在而控制器不存在为loss(丢失)，系统中不存在而控制器中存在为found(发现)
    creation_time = IntegerField(default=int(time()))
    is_del = BooleanField(default=False)

    class Meta:
        table_name = 'sdn_device'


class Port(MetaBaseModel):
    """
    可用物理端口
    """
    name = CharField(null=True)
    mac = TextField(null=True)
    max_speed = CharField(null=True)
    port_no = SmallIntegerField(null=True)
    status = CharField(choices=['UP', 'DOWN'], default='DOWN')
    description = TextField(null=True)  # 描述信息
    note = TextField(null=True)  # 备注
    crc = IntegerField(default=0)
    usage = CharField(choices=['idle', 'management_endpoint', 'nni_link',
                               'vlan_based_endpoint', 'port_based_endpoint', 'untag_based_endpoint'], default='idle',
                      null=True)
    available = BooleanField(default=False)
    access_mode = CharField(choices=['idle', 'direct', 'shared'], default='idle', null=True)
    # 这里要把Port和Node做级联绑定，Node删除将会导致所有关联Port删除
    node = ForeignKeyField(Node, backref='ports', null=True)
    device = ForeignKeyField(Device, backref='ports', null=True)
    exist_status = CharField(
        choices=['loss', 'found', 'normal'],
        default='normal')  # 标记端口在控制器和系统数据库中的状态，系统中存在而控制器不存在为loss(丢失)，系统中不存在而控制器中存在为found(发现)
    is_del = BooleanField(default=False)

    class Meta:
        table_name = 'sdn_port'


class LogicPort(MetaBaseModel):
    # 机房配置
    id = UUIDField(primary_key=True, default=str(uuid4()))
    name = CharField()
    tenant = ForeignKeyField(Tenant, backref='logic_ports')
    access_type = CharField(choices=['独享', '共享'], default='共享')
    start_time = IntegerField()
    end_time = IntegerField()
    optional_status = BooleanField(default=True)  # 端口可选状态，开业务选择逻辑口的时候选成透传，则为False (被占用，其他用户不可使用)
    description = TextField(null=True)
    no = TextField(null=True)  # 编号
    sync_status = CharField(max_length=64, null=True, default=0)  # 是否同步
    sync_time = IntegerField()
    is_del = BooleanField(default=False)
    usable = BooleanField(default=True)
    creation_time = IntegerField(default=int(time()))

    class Meta:
        table_name = 'sdn_logic_port'

    def get_status(self):
        status_list = [True if info.port.status == 'UP' else False for info in self.physical_ports]
        if all(status_list):
            return 'UP'
        elif all(bool(1 - status) for status in status_list):
            return 'DOWN'
        else:
            return '异常'

    def get_standard_obj(self):
        import time
        info = model_to_dict(self, only=[LogicPort.id, LogicPort.no])
        info['id'] = str(info['id'])
        info['note'] = self.description
        info['vll_show_name'] = self.name
        info['org'] = {"id": str(self.tenant.id),
                       "name": self.tenant.name}
        infos = LogicPortInfo.select().where(LogicPortInfo.logic_port_id == self.id)
        endpoint_show_name = ','.join([i.node.name for i in infos])
        endpoint_city_name = ','.join([i.node.dc.city.name for i in infos])
        endpoint_region_name = ','.join([i.node.dc.region.name for i in infos])
        endpoint_dc_name = ','.join([i.node.dc.name for i in infos])
        open_time = self.start_time
        if open_time:
            open_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(open_time))
        else:
            open_time = None
        expiration_time = self.end_time
        if expiration_time:
            expiration_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(expiration_time))
        else:
            expiration_time = None
        info['endpoint_show_name'] = endpoint_show_name
        info['endpoint_city_name'] = endpoint_city_name
        info['endpoint_region_name'] = endpoint_region_name
        info['endpoint_dc_name'] = endpoint_dc_name
        info['open_time'] = open_time
        info['expiration_time'] = expiration_time
        info['endpoint_show_bandwidth'] = ''
        status = EnumData.get_or_none(EnumData.value == self.get_status(), EnumData.type == 'port')
        if status:
            info['status'] = status.key
        else:
            info['status'] = self.get_status()
        info['type'] = 'port'
        info['points'] = []
        physical_ports = []
        for i in infos:
            physical_port = {}
            node = Node.get_or_none(id=i.node_id)
            physical_port['node'] = {'id': node.id, 'name': node.name, 'controller_id': node.controller_id}
            device = Device.get_or_none(id=i.device_id)
            physical_port['device'] = {'id': device.id, 'hostname': device.hostname, 'sign': device.sign}
            port = Port.get_or_none(id=i.port_id)
            physical_port['port'] = {'id': port.id, 'port_no': port.port_no, 'status': port.status}
            physical_ports.append(physical_port)

        info['physical_ports'] = physical_ports
        info['charge_type'] = 'year_month'
        info['charge_param'] = {
            "period": "year",  # 计费周期，可以为以下值：month/year/half-year/quarter
            "period_fee": '',  # 周期费用
            "once_fee": '',  # 一次性费用
            "money_unit": "人民币",  # 货币单位
        }
        info["no"] = '123'
        # if self.sync_status == "2":
        #     if self.no:
        #         info["no"] = json.loads(self.no)
        #     else:
        #         no = []
        #         from apps.utils.views import generate_no
        #         no.append(generate_no('LogicPort', type='port'))
        #         self.no = json.dumps(no)
        #         info['no'] = no[0]
        #         self.save()
        return info


class LogicPortInfo(MetaBaseModel):
    id = UUIDField(primary_key=True, default=str(uuid4()))
    creation_time = IntegerField(default=int(time()))
    logic_port = ForeignKeyField(LogicPort, backref='physical_ports')

    # 节点信息
    node = ForeignKeyField(Node, backref='logic_ports')
    device = ForeignKeyField(Device, backref='logic_ports')
    port = ForeignKeyField(Port, backref='logic_ports')

    # 物理端口对接客户信息
    position = CharField(null=True)  # 机房位置
    rack = CharField(null=True)  # 机柜编号
    device_type = CharField(choices=['交换机', '路由器', '防火墙'], null=True)  # 用户设备类型
    port_type = CharField(choices=['万兆单模', '万兆多模', '千兆单模', '千兆多模', '千兆电口', '百G单模', '百G多模'],
                          null=True)  # 端口类型
    description = TextField(null=True)

    class Meta:
        table_name = 'sdn_logic_port_info'


class Endpoint(MetaBaseModel):
    """
    VLL端点信息（D2D、D2C）
    """
    id = UUIDField(primary_key=True, default=str(uuid4()))
    name = CharField(choices=['A端', 'Z端'], null=True)
    node = ForeignKeyField(Node, backref='endpoints')
    logic_port = ForeignKeyField(LogicPort, backref='endpoints')
    vll = ForeignKeyField(Vll, backref='endpoints')
    controller_port_id = CharField(null=True)
    controller_id = IntegerField(null=True)  # 控制器侧业务id
    status = CharField(choices=['creating', 'failure', 'success'], default='creating')
    vlan = IntegerField()  # -1代表透传，0代表untag，其他为具体vlan值
    egress = BooleanField(default=False)  # 是否设置出向限速
    description = TextField(null=True)
    usable = BooleanField(default=True)
    is_del = BooleanField(default=False)

    class Meta:
        table_name = 'sdn_endpoint'


class CloudConfig(MetaBaseModel):
    id = UUIDField(primary_key=True, default=str(uuid4()))
    type = CharField()  # 公有云类型
    name = CharField()  # 链路名称
    region = CharField()  # 区域
    access_point = CharField()  # 接入点id
    bandwidth = IntegerField()
    description = TextField(null=True)

    # 对接信息
    node = ForeignKeyField(Node, backref='clouds')
    logic_port = ForeignKeyField(LogicPort, backref='clouds')
    # 接口驱动
    interface_driver = CharField(choices=['CloudDriver', 'AliDriver', 'TencentDriver'],
                                 default='AliDriver')
    api_url = CharField(null=True)  # 创建业务用的url(阿里云中的vbr)
    api_token = CharField(null=True)  # 阿里云中AccessKeyId+AccessKeySecret，腾讯云中的secretid:secretkey
    api_uuid = CharField(null=True)  # 阿里云|腾讯云中的物理专线id
    extension = CharField(null=True)
    get_speed_key = CharField(null=True)  # 获取流量的键值
    instant_speed = CharField(null=True)  # 即时流量
    is_del = BooleanField(default=False)

    class Meta:
        table_name = 'sdn_cloud_config'


class CloudEndpoint(MetaBaseModel):
    """
    VLL云端点信息（ali|tencent）
    """
    id = UUIDField(primary_key=True, default=str(uuid4()))
    cloud_type = CharField()
    region = CharField()
    vll = ForeignKeyField(Vll, backref='cloud_endpoints')
    cloud_config = ForeignKeyField(CloudConfig)
    owner_id = CharField(null=True)  # 阿里云账户id|腾讯云账户id
    vlan = IntegerField(null=True)  # -1代表透传，0代表untag，其他为具体vlan值
    egress = BooleanField(default=False)  # 是否设置出向限速
    controller_port_id = CharField(null=True)
    controller_id = IntegerField(null=True)  # 控制器侧业务id
    cloud_relation_id = CharField(null=True)  # 相关云创建业务返回的id，阿里云vbrid|腾讯专用通道id
    name = CharField(null=True)
    local_gateway_ip = CharField(null=True)
    peer_gateway_ip = CharField(null=True)
    peering_subnet_mask = CharField(null=True)
    extension = CharField(null=True)
    description = TextField(null=True)
    status = CharField(choices=['creating', 'failure', 'success'], default='creating')
    cloud_status = CharField(null=True)  # 对应的云是否创建成功：success 成功 failure:失败原因 ：失败
    usable = BooleanField(default=True)
    is_del = BooleanField(default=False)

    class Meta:
        table_name = 'sdn_cloud_endpoint'


class VllEndpointExtension(MetaBaseModel):
    id = UUIDField(primary_key=True, default=str(uuid4()))
    type = CharField(choices=['vll', 'endpoint', 'cloud_endpoint'])
    relation_id = CharField()  # 关联id，业务或端点或云端点的id
    bandwidth = IntegerField()  # 不可为空
    charge_mode = CharField(choices=['year_month', '95_charge', 'man_made'],
                            default='year_month')  # 计费方式,year_month包年包月，95_charge九五计费，man_made人工结算
    charge_time = IntegerField(default=int(time()), null=True)  # 计费时间
    expiration_time = IntegerField(null=True)  # 过期时间（开始时间+？）
    is_del = BooleanField(default=False)

    class Meta:
        table_name = 'sdn_vll_endpoint_extension'


class ControllerDevice(MetaBaseModel):
    class Meta:
        table_name = 'controller_device'


class ControllerPort(MetaBaseModel):
    device = ForeignKeyField(column_name='device_id', field='id', model=ControllerDevice)
    port = IntegerField()
    updated_at = DateTimeField()

    class Meta:
        table_name = 'controller_port'
        indexes = (
            (('device', 'port', 'delete_id'), True),
        )
